package szoftlab4;

import java.util.*;

/**
 * Kompozit, azaz összetett elem. Építőelemeket tartalmaz, ütemezi a jelterjedést
 * önmagán belül, és létezhet kimenete illetve bemenete.
 * @author Peti
 */
public class KompozitElem extends Asztal implements AktivEpitoelem, NemVezetekEpitoelem
{
    /**
     * A kompozit elemhez tartozó bemenetek listája.
     */
    protected ArrayList<Bemenet> bemenetek;

    /**
     * A kompozit elemhez tartozó kimenetek listája.
     */
    protected ArrayList<Kimenet> kimenetek;

    /**
     * A kompozit elemet tartalmazó asztal.
     */
    protected Asztal asztal;

    /**
     * Tartalmazza a kifele mutatott bemenetekhez tartozó belső szabad bemeneteket.
     */
    protected Map<Bemenet, Bemenet> bemenetiCsatolas;

    /**
     * Tartalmazza a kifele mutatott kimenetekhez tartozó belső szabad kimeneteket.
     */
    protected Map<Kimenet, Kimenet> kimenetiCsatolas;

    /**
     * A kompozit elem konstruktora.
     * Az s bemenete alapján létrehozza a hálózathoz szükséges elemeket, és elvégzi
     * a szükséges építőelemek összekötését.
     *
     * @param s
     * A hálózat létrehozásához szükséges adatokat tartalmazó String
     * (építőelemek és csatlakozásaik).
     */
    public KompozitElem(String s)
    {
        super(s);
        for(Epitoelem e:elemek)
        {
            for(int i=0;i<e.szabadBemenetek().size();i++)
            {
                bemenetek.add(new Bemenet(null));
            }
            for(int i=0;i<e.szabadKimenetek().size();i++)
            {
                kimenetek.add(new Kimenet());
            }
        }

        bemenetiCsatolas = new HashMap<Bemenet, Bemenet>();
        for(Bemenet b:bemenetek)
        {
            bemenetiCsatolas.put(b,null); //bemeneti nyelv szerint
        }

        kimenetiCsatolas = new HashMap<Kimenet, Kimenet>();
        for(Kimenet k:kimenetek)
        {
            kimenetiCsatolas.put(k,null); //bemeneti nyelv szerint
        }
    }

    public Asztal getAsztal()
    {
        return asztal;
    }

    public void szamol() throws KritikusVersenyhelyzetException
    {
        for(Bemenet b:bemenetek)
        {
            bemenetiCsatolas.get(b).setErtek(b.getErtek());
        }
        while(!esemenysor.isEmpty())
        {
            sortKiertekel();
            for(ArrayList<Boolean> multbeli:allapot)
            {
                if(multbeli.equals(allapot.get(allapot.size()-1))
                        && multbeli != allapot.get(allapot.size()-1))
                    throw new KritikusVersenyhelyzetException();
            }
        }
        for(Kimenet k:kimenetek)
        {
            kimenetiCsatolas.get(k).setErtek(k.getErtek());
        }
    }

    public void accept(EpitoelemAktivVisitor v)
    {
        v.visit(this);
    }

    public void csatlakozik(int bemenetIndexe, Epitoelem cel, int kimenetIndexe)
    {
        bemenetek.get(bemenetIndexe).csatlakozik(this, cel, bemenetIndexe, kimenetIndexe);
    }

    public Kimenet csatlakozik(int bemenetIndexe, Vezetek innen, int kimenetIndexe)
    {
        return kimenetek.get(kimenetIndexe).csatlakozik(this, innen, bemenetIndexe);
    }

    public Kimenet csatlakozik(int bemenetIndexe, NemVezetekEpitoelem innen, int kimenetIndexe)
    {
        return kimenetek.get(kimenetIndexe).csatlakozik(this, innen, bemenetIndexe);
    }

    public void leptet()
    {
        for(Epitoelem e:elemek)
        {
            e.accept(lepteto);
        }
    }

    public void visszaallit()
    {
        for(Epitoelem e:elemek)
        {
            e.accept(visszaallito);
        }
    }

    /**
     * A szabadon maradt, azaz semmilyen kimenethez nem csatlakozó bemenetek listáját adja vissza.
     * @return
     * A szabad bemenetek listája.
     */
    public ArrayList<Bemenet> szabadBemenetek()
    {
        ArrayList<Bemenet> eredmeny = new ArrayList<Bemenet>();
        for(Bemenet b:bemenetek)
        {
            if(b.getKimenet()==null) eredmeny.add(b);
        }
        return eredmeny;
    }

    /**
     * A szabadon maradt, azaz semmilyen bemenethez nem csatlakozó kimenetek listáját adja vissza.
     * @return
     * A szabad kimenetek listája.
     */
    public ArrayList<Kimenet> szabadKimenetek()
    {
        ArrayList<Kimenet> eredmeny = new ArrayList<Kimenet>();
        for(Kimenet k:kimenetek)
        {
            if(k.getBemenetek().isEmpty()) eredmeny.add(k);
        }
        return eredmeny;
    }
    
}
